package org.jsserv;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.jsserv.control.DOMEventController;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;

/**
 * Intercepts non-{@link DOMEventController} Controllers to grab their output to intialize the client's {@link DOMState}.
 * @author shelmberger
 *
 */
public class DOMInterceptor implements HandlerInterceptor, ApplicationContextAware
{
    private InterceptorStrategy interceptorStrategy=new EverythingButEventController();
    
    private ViewResolver viewResolver;

    private ApplicationContext applicationContext;

    protected static Logger log = Logger.getLogger(DOMInterceptor.class);

    /**
     * Sets an {@link InterceptorStrategy} which decides which request should be intercepted to
     * (re)initialize the user's {@link DOMState}.
     * @param interceptorStrategy
     */
    public void setInterceptorStrategy(InterceptorStrategy interceptorStrategy)
    {
        this.interceptorStrategy = interceptorStrategy;
    }
    
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object o,
        Exception e) throws Exception
    {
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object o,
        ModelAndView mav) throws Exception
    {
        if (interceptorStrategy.intercept(request, response, o, mav))
        {
            DOMResponseWrapper wrapper = new DOMResponseWrapper(response);
            View v = viewResolver.resolveViewName(mav.getViewName(), request.getLocale());
            v.render(mav.getModel(), request, wrapper);
            
            DOMState session=(DOMState)applicationContext.getBean("jsSession");
            session.createDocument(request.getRequestURI(), request.getContextPath(), wrapper.getOutput());
            DOMEventController.sendDOM(session, response);
        }
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o)
        throws Exception
    {
        return true;
    }

    public void setApplicationContext(ApplicationContext context) throws BeansException
    {
        this.applicationContext=context;
        
        Map<String, ViewResolver> map = (Map<String, ViewResolver>)context.getBeansOfType(ViewResolver.class);

        for (ViewResolver v : map.values())
        {
            viewResolver=v;
            break;
        }
    }
    
    /**
     * Strategy Interface for the request interception. 
     */
    public static interface InterceptorStrategy
    {
        /**
         * Returns true if the request should be intercepted to (re)initialize the user's {@link DOMState}.
         * @return
         */
        boolean intercept(HttpServletRequest request, HttpServletResponse response, Object o,
            ModelAndView mav) throws Exception;
    }
    
    private static class EverythingButEventController implements InterceptorStrategy
    {

        public boolean intercept(HttpServletRequest request, HttpServletResponse response, Object o,
            ModelAndView mav)
        {
            return (!(o instanceof DOMEventController));
        }
        
    }
}
